package processes

import (
	"encoding/json"
	"fmt"
	"go_code/project01_basic/chapter15_qq/message"
	"go_code/project01_basic/chapter15_qq/server/utils"
	"io"
	"net"
	"os"
	"strings"

	"go_code/project01_basic/chapter15_qq/server/model"
)

type UserProcess struct {
	Conn       net.Conn
	UserId     int
	NickName   string
	UserStatus int `json:"userStatus"`
}

func (u *UserProcess) SeverProcessLogin(mes *message.Message) (err error) {
	//解析登录信息
	var loginMes message.LoginMes
	err = json.Unmarshal([]byte(mes.Data), &loginMes)
	if err != nil {
		fmt.Println("json.Unmarshal err=", err)
		return
	}

	//返回登录结果
	resMes := &message.Message{}
	resMes.Type = message.LoginResMesType
	var loginResMes message.LoginResMes

	user, err := model.MyUserDao.Login(loginMes.UserId, loginMes.UserPwd)

	if err != nil {
		if err == model.ErrorUNE {
			loginResMes.Code = 404
			loginResMes.Error = err.Error()
		} else if err == model.ErrorUPWD {
			loginResMes.Code = 403
			loginResMes.Error = err.Error()
		} else {
			loginResMes.Code = 505
			loginResMes.Error = "服务器内部错误"
		}
	} else {
		loginResMes.Code = 200
		//添加用户到在线用户
		u.UserId = loginMes.UserId
		u.NickName = user.UserName
		u.UserStatus = message.UserOnline
		UsersMgr.AddOnlineUser(u)
		//更新全部用户信息
		AllUsers.Users[loginMes.UserId].UserStatus = message.UserOnline
		AllUsers.Users[loginMes.UserId].Conn = u.Conn
		//添加在线用户信息到登录结果
		for _, v := range UsersMgr.onlineUsers {
			if v.UserStatus == message.UserOnline {
				loginResMes.OnlineUsers = append(loginResMes.OnlineUsers, fmt.Sprint(v.UserId, ":", v.NickName))
			}
		}

		//通知其他用户我上线了
		u.NotifyOthersOnlineUser(u.UserId, u.NickName)

		fmt.Println(user.UserName, "登录成功")

	}

	//序列化结果
	data, err := json.Marshal(loginResMes)
	if err != nil {
		return
	}
	resMes.Data = string(data)
	//传递信息
	tf := &utils.Transfer{
		Conn: u.Conn,
	}
	tf.Delivery(resMes)

	//推送留言信息
	model.MyUserDao.LeaveSmsPut(u.UserId, u.Conn)

	return nil
}

func (u *UserProcess) SeverProcessRegister(mes *message.Message) (err error) {
	//解析登录信息
	var registerMes message.RegisterMes
	err = json.Unmarshal([]byte(mes.Data), &registerMes)
	if err != nil {
		fmt.Println("json.Unmarshal err=", err)
		return
	}

	//返回登录结果
	resMes := &message.Message{}
	resMes.Type = message.RegisterResMesType
	var registerResMes message.RegisterResMes

	err = model.MyUserDao.Register(&registerMes.User)

	if err != nil {
		if err == model.ErrorUE {
			registerResMes.Code = 180
			registerResMes.Error = err.Error()
		} else {
			registerResMes.Code = 505
			registerResMes.Error = "服务器内部错误"
		}
	} else {
		registerResMes.Code = 200
		fmt.Println(registerMes.User.UserName, "注册成功")
	}

	//序列化结果
	data, err := json.Marshal(registerResMes)
	if err != nil {
		return
	}
	resMes.Data = string(data)
	//传递信息
	tf := &utils.Transfer{
		Conn: u.Conn,
	}
	tf.Delivery(resMes)

	return nil
}

func (u *UserProcess) ServerProcessOffline(mes *message.Message) (err error) {
	//解析下线信息
	var offlineMes message.OfflineMes
	err = json.Unmarshal([]byte(mes.Data), &offlineMes)
	if err != nil {
		fmt.Println("json.Unmarshal err=", err)
		return
	}

	//服务端更新在线信息
	fmt.Printf("%v下线了\n", offlineMes.UserId)
	delete(UsersMgr.onlineUsers, offlineMes.UserId)
	AllUsers.Users[offlineMes.UserId].UserStatus = message.UserOffline

	//更新其他用户的在线信息
	for _, up := range UsersMgr.onlineUsers {
		tf := &utils.Transfer{
			Conn: up.Conn,
		}
		err = tf.Delivery(mes)
		if err != nil {
			fmt.Println("notify offlineMes err=", err)
			return
		}
	}
	return nil
}

func (u *UserProcess) NotifyOthersOnlineUser(userId int, nickName string) {
	for id, up := range UsersMgr.onlineUsers {
		if id == userId {
			continue
		}
		up.NotifyMeOnline(userId, nickName)
	}
}

func (u *UserProcess) NotifyMeOnline(userId int, nickName string) {
	var mes message.Message
	mes.Type = message.NotifyUserStatusMesType

	var notifyUserStatusMes message.NotifyUserStatusMes
	notifyUserStatusMes.UserId = userId
	notifyUserStatusMes.UserName = nickName
	notifyUserStatusMes.Status = message.UserOnline

	//序列化结果
	data, err := json.Marshal(notifyUserStatusMes)
	if err != nil {
		return
	}
	mes.Data = string(data)

	//传递信息
	tf := &utils.Transfer{
		Conn: u.Conn,
	}
	err = tf.Delivery(&mes)
	if err != nil {
		fmt.Println("NotifyMeOnline err=", err)
		return
	}
}

func (u *UserProcess) SeverProcessFileMes(fileMes *message.FileMes) (err error) {
	fileMes.FileName = "D:/APP/goproject/src/go_code/project01_basic/chapter15_qq/server/client_file/" + fileMes.FileName
	//按照文件名创建新文件
	f, err := os.Create(fileMes.FileName)
	if err != nil {
		fmt.Println("os.Create err:", err)
		return
	}
	defer f.Close()

	//从网络中读数据，写入本地文件
	buf := make([]byte, 8192)
	for {
		n, _ := u.Conn.Read(buf)

		//写入本地文件，读取多少写多少
		f.Write(buf[:n])

		if n < 8192 {
			fmt.Println("接收文件完成")
			c := strings.Split(fileMes.FileName, "/")
			u.AsksIsAcceptFile(c[len(c)-1], fileMes.UserId)
			return
		}
	}
}

func (u *UserProcess) AsksIsAcceptFile(fileName string, user int) (err error) {
	for id, up := range UsersMgr.onlineUsers {
		if id == user {
			continue
		}
		up.SendFile(fileName)
	}
	return
}

func (u *UserProcess) SendFile(filePath string) (err error) {
	//封装表头表示要发送文件
	fileMes := &message.FileMes{
		UserId:   000,
		FileName: filePath,
	}
	data, err := json.Marshal(fileMes)
	if err != nil {
		fmt.Println("json.Marshal err=", err)
		return
	}
	mes := &message.Message{
		Type: message.FileMesType,
		Data: string(data),
	}
	tf := &utils.Transfer{
		Conn: u.Conn,
	}

	//只读打开文件
	filePath = "D:/APP/goproject/src/go_code/project01_basic/chapter15_qq/server/client_file/" + filePath
	f, err := os.Open(filePath)
	if err != nil {
		fmt.Println("os.Open err:", err)
		return
	}
	defer f.Close()

	//发送一个表头，表示下面要发送文件
	err = tf.Delivery(mes)
	if err != nil {
		fmt.Println("com.Delivery err=", err)
		return
	}

	//从本文件中写数据，写给网络接收端。读多少写多少
	buf := make([]byte, 8192)
	for {
		n, err := f.Read(buf)
		if err != nil {
			if err == io.EOF {
				fmt.Println("文件发送成功")
			} else {
				fmt.Println("f.Read err:", err)
			}
			return err
		}
		//写到网络socket中
		_, err = u.Conn.Write(buf[:n])
		if err != nil {
			fmt.Println("conn.Write err:", err)
			return err
		}
	}
}
